//
//  HomeViewController.swift
//  WCHBLEApp
//
//  Created by 娟华 胡 on 2021/3/16.
//

import UIKit
import SnapKit
import XappKit
import XappBase
import CoreBluetooth
import WCHBLELibrary
import MessageUI

class HomeViewController: MH_VC_BaseViewController {
    

    @IBOutlet weak var segmentioView: Segmentio!
    @IBOutlet weak var tableView: MH_V_RefreshTableView!
    @IBOutlet weak var bondedTableView: UITableView!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var contentWidthLayout: NSLayoutConstraint!
    
    private var WCHManager:WCHBLEManager?
    private var connectPeripheral:CBPeripheral?
    private var devicesArray:[PeripheralModel] = [PeripheralModel]()
    private var bondedArray:NSMutableArray = NSMutableArray()
    private var servicesArray:[CBService] = [CBService]()
    
    var cachedVirtualPeripherals: [VirtualPeripheral] {
        return VirtualPeripheralStore.shared.cachedVirtualPeripheral
    }
    var selectedVirtualPeriperalIndex: Int = -1
    
    private var serviceCharacter:[String:[CBCharacteristic]] = [String:[CBCharacteristic]]()
    private var connectedArray:[String] = [String]()
    private var identifiers:[UUID] = [UUID]()
    private weak var serviceVC:PeripheralServiceViewController?
    private var writeCallBack:writeDataCallBack?
    
    var preferences: Preferences? {
        return PreferencesStore.shared.preferences
    }
    
    private var isScroll:Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "BLE调试助手"
        _=self.leftBarItem(with: UIImage.init(named: "menu"), selector: #selector(menuAction))
        _=self.rightBarItem(with: "Filter", selector: #selector(filterAction))
        // Do any additional setup after loading the view.
        print("Home开始加载")
        self.setupHome()
    }
    
    func setupHome() {
        self.setupScrollView()
//        self.readBondedPeripheral()
        
        self.WCHManager = WCHBLEManager.getInstance()
        self.WCHManager?.delegate = self
        self.WCHManager?.isDebug = true
        
        self.contentWidthLayout.constant = UIScreen.main.bounds.width
        self.segmentioView.setup(content: self.segmentioContent(), style: .onlyLabel, options:SegmentioBuilder.segmentioOptions(segmentioStyle: .onlyLabel))
        self.segmentioView.selectedSegmentioIndex = 0
        segmentioView.valueDidChange = { [weak self] _, segmentIndex in
            guard let wself = self else { return }
            let scrollViewWidth = wself.scrollView.frame.width
            let contentOffsetX = scrollViewWidth * CGFloat(segmentIndex)
            wself.scrollView.setContentOffset(
                CGPoint(x: contentOffsetX, y: 0),
                animated: true
            )
            
            if (segmentIndex == 1) {
//                let periArray = wself.WCHManager?.retrievePeripherals(withIdentifiers: wself.identifiers)
//                wself.bondedArray.removeAllObjects()
//                wself.bondedArray.addObjects(from: periArray ?? [])
//                wself.bondedTableView.reloadData()
                
            }
        }
        
        if (nil == self.writeCallBack) {
            self.writeCallBack = {[weak self] (count) in
                guard let wself = self else { return }
            
                DispatchQueue.main.async {
                    wself.serviceVC?.writeCount(count: Int64(count))
                }
                
            }
        }
    }
    
    private func setupScrollView() {
        self.scrollView.isPagingEnabled = true
        self.scrollView.delegate = self
        
        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.tableView.tableFooterView = UIView()
        self.tableView.setTableViewRefreshHeader()
        self.tableView.refreshHeaderHandler = { [weak self] in
            guard let wself = self else { return }
            wself.devicesArray.removeAll()
            wself.scanAllPeripheral()
          
        }
        
        self.bondedTableView.delegate = self
        self.bondedTableView.dataSource = self
        self.bondedTableView.tableFooterView = UIView()
    }
    
    @objc func menuAction() {
        let sideMenuVC = SideMenuViewController.init(nibName: "SideMenuViewController", bundle: Bundle.init(for: SideMenuViewController.self))
        sideMenuVC.showSideMenu(
            viewController: self,
            currentNav: self.navigationController!,
            sideMenuDidHide: { [weak self]  in
                self?.dismiss(
                    animated: false,
                    completion: {

                    }
                )
            }
        )

        sideMenuVC.sendEmail = { [weak self] in
            guard let wself = self else { return }
            if MFMailComposeViewController.canSendMail() {
                let mail = MFMailComposeViewController()
                mail.mailComposeDelegate = wself
                mail.setToRecipients(["tech@wch.cn"])
//                mail.setMessageBody("<p>You're so awesome!</p>", isHTML: true)
                wself.navigationController?.present(mail, animated: true, completion: nil)
            } else {
                // show failure alert
            }
        }
        
    }
    
    @objc func filterAction() {
        let filterVC = FilterViewController.init(nibName: "FilterViewController", bundle: Bundle.init(for: FilterViewController.self))
        filterVC.filterCallBack = { [weak self] in
            guard let wself = self else { return }
            wself.scanAllPeripheral()
        }
        filterVC.sortedCallBack = { [weak self] in
            guard let wself = self else { return }
            wself.devicesArray = wself.devicesArray.sorted {
                $0.RSSI.intValue > $1.RSSI.intValue
            }
            wself.tableView.reloadData()
        }
        self.navigationController?.pushViewController(filterVC, animated: true)
    }
    
    private func segmentioContent() -> [SegmentioItem] {
        return [
            SegmentioItem(title: "Peripherals", image: nil),
            SegmentioItem(title: "Virtual Devices", image: nil),
        ]
    }
    
    private func scanAllPeripheral() {
        self.devicesArray.removeAll()
        self.tableView.reloadData()
        self.WCHManager?.stopScan()
        self.WCHManager?.startScan(nil)
    }
    
    private func wchScanPeripheral() {
        self.devicesArray.removeAll()
        self.tableView.reloadData()
        self.WCHManager?.stopScan()
        self.WCHManager?.startScanCH914X()
    }
    
    private func stopScan() {
        self.WCHManager?.stopScan()
    }
    
    private func setConnectSuccess() {
        let sVC = PeripheralServiceViewController.init(nibName: "PeripheralServiceViewController", bundle: Bundle.init(for: PeripheralServiceViewController.self))
        sVC.services = self.servicesArray
        sVC.serviceSendData = { [weak self] (data, character) in
            guard let wself = self else { return }
            wself.WCHManager?.write(data, peripheral: wself.connectPeripheral, writeForChar: character, writeCallBack:wself.writeCallBack)
        }
        sVC.serviceDisConnect = { [weak self] in
            guard let wself = self else { return }
            wself.WCHManager?.disconnect(wself.connectPeripheral)
        }
        sVC.serviceNotify = { [weak self] (open, character) in
            guard let wself = self else { return }
            if (open) {
                wself.WCHManager?.peripheralNotify(wself.connectPeripheral, setNotifyForChar: character)
            }else {
                wself.WCHManager?.peripheralNotify(wself.connectPeripheral, cancleNotifyForChar: character)
            }
        }
        sVC.serviceReadData = {[weak self] (character) in
            guard let wself = self else { return }
            wself.WCHManager?.readData(wself.connectPeripheral, readValueForChar: character);
        }
        
        sVC.serviceLog = { [weak self] in
            guard let wself = self else { return }
            
            let array = wself.WCHManager?.readLog() as NSArray?
            wself.serviceVC?.logView?.setLog(log: array)
        }
        sVC.serviceBackAction = { [weak self] in
            guard let wself = self else { return }
            wself.scanAllPeripheral()
        }
        self.navigationController?.pushViewController(sVC, animated: true)
        self.serviceVC = sVC
    }
    
    private func saveBondedPeripheral(peripheral:CBPeripheral?) {
        if (peripheral == nil) {
            return
        }
       
        //是否是已经连接过的设备
        var flag:Bool = false
        for (_, value) in self.connectedArray.enumerated() {
            let connectedPeripheral = self.phraseConnectedPeripheral(connected: value)
            if (peripheral?.identifier.uuidString == connectedPeripheral.0) {
                flag = true
                break
            }
        }
        
        if (!flag) {
            for (_, value) in self.devicesArray.enumerated() {
                let peripheralModel = value
                if (peripheral?.identifier == peripheralModel.peripheral.identifier) {
                    self.bondedArray.add(peripheralModel)
                    let dict:[String:String] = ["uuid":(peripheral?.identifier.uuidString ?? ""), "name":(peripheral?.name ?? "")]
                    
                    let dictData = try? JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions.init())
                    let dictStr = String.init(data: dictData ?? Data(), encoding: .utf8)
                    self.connectedArray.append(dictStr ?? "")
                    
                    break
                }
            }
            
            let defaults = UserDefaults.standard
            let jsonData = try? JSONSerialization.data(withJSONObject: self.connectedArray, options:[])
            let jsonStr = String(data: jsonData!, encoding: String.Encoding.utf8)
            defaults.setValue(jsonStr, forKey: "bondedPeripheral")
            defaults.synchronize()
        }
    }
    
    private func readBondedPeripheral() {
        let defaults = UserDefaults.standard
        let jsonStr = defaults.object(forKey: "bondedPeripheral") as? String ?? ""
        let data = jsonStr.data(using: .utf8)
        let array:[String]? = try? JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.init()) as? [String] ?? [String]()
    
        self.connectedArray = array ?? [String]()
        for i in 0 ..< (array?.count ?? 0) {
            let peripheral = self.phraseConnectedPeripheral(connected: array![i])
            self.identifiers.append(UUID.init(uuidString: peripheral.0)!)
        }
        
        defaults.synchronize()
    }
    
    private func phraseConnectedPeripheral(connected:String) -> (String, String) {
        let data = connected.data(using: .utf8) ?? Data()
        let dict:Dictionary<String, Any>? = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? Dictionary<String, Any> ?? Dictionary<String, Any>()
        let uuid = dict?["uuid"] as? String ?? ""
        let name = dict?["name"] as? String ?? ""
        return (uuid, name)
    }
}

extension HomeViewController:BLEAssistDelegate {

    func bleManagerDidDiscover(_ peripheral: CBPeripheral?, advertisementData: [String : Any]?, rssi RSSI: NSNumber?) {
        
        if (peripheral == nil || advertisementData == nil || RSSI == nil) {
            return
        }
        self.tableView.endHeaderRefersh()
        let peripheralInfo = PeripheralModel.init(peripheral!)
        if (!self.devicesArray.contains(peripheralInfo)) {
            let nowTimeInterval = Date().timeIntervalSince1970
            
            if let preference = preferences, preference.needFilter {
                if RSSI!.intValue != 127, RSSI!.intValue > preference.filter {
                    peripheralInfo.advertisementData = advertisementData!
                    peripheralInfo.RSSI = RSSI!
                    peripheralInfo.lastUpdatedTimeInterval = nowTimeInterval
                    self.devicesArray.append(peripheralInfo)
                }
            } else {
                peripheralInfo.advertisementData = advertisementData!
                peripheralInfo.RSSI = RSSI!
                peripheralInfo.lastUpdatedTimeInterval = nowTimeInterval
                self.devicesArray.append(peripheralInfo)
            }
            // If the last update within one second, then ignore it
//            guard nowTimeInterval - peripheralInfo.lastUpdatedTimeInterval >= 1.0 else {
//                return
//            }
            
         
        }else {
            guard let index = self.devicesArray.firstIndex(of: peripheralInfo) else {
                return
            }
            let originPeripheralInfo = self.devicesArray[index]
            let nowTimeInterval = Date().timeIntervalSince1970
            
            originPeripheralInfo.lastUpdatedTimeInterval = nowTimeInterval
            originPeripheralInfo.RSSI = RSSI!
            originPeripheralInfo.advertisementData = advertisementData!
            
        }
        
        if (!isScroll) {
            self.tableView.reloadData()
        }
       
    }
    
    func bleManagerPeriphearl(_ peripheral: CBPeripheral?, services: [CBService]?, error: Error?) {
        if (nil == error) {
            self.servicesArray.removeAll()
            self.servicesArray = services ?? [CBService]()
            self.setConnectSuccess()
            self.serviceVC?.title = peripheral?.name
        }
    }
    
    func bleManagerService(_ service: CBService?, characteristics: [CBCharacteristic]?, error: Error?) {
        if (nil == error) {
            self.serviceCharacter[service?.uuid.uuidString ?? ""] = characteristics
            self.serviceVC?.servicesCharacterList(list: self.serviceCharacter)
        }
    }
    
    func bleManagerUpdateValue(forCharacteristic peripheral: CBPeripheral?, characteristic: CBCharacteristic?, error: Error?) {
        if (nil == error) {
            if (characteristic?.isNotifying ?? false) {
                self.serviceVC?.readCharacterValue(character: characteristic)
            }
        }
    }
    
    func bleManagerDidUpdateState(_ error: Error?) {
        let nsError = error as NSError?
        let errorInfo = nsError?.userInfo
        print(errorInfo?["NSUnderlyingError"] as? String ?? "未知错误")
        _=self.showFailedMessage(errorInfo?["NSUnderlyingError"] as? String ?? "未知错误")
    }
    
    func bleManagerDidPeripheralConnectUpateState(_ peripheral: CBPeripheral?, error: Error?) {
        self.hideHud()
        if (nil == error) {
            _=self.showSuccessMessage("连接成功")
//            self.saveBondedPeripheral(peripheral: peripheral)
            self.connectPeripheral = peripheral
      
            self.WCHManager?.readRSSI(peripheral, rssiCallBack: { (number) in
                print("读取到了信号强度",Int(truncating: number ?? 0))
            })
        }else {
            let nsError = error as NSError?
            let errorInfo = nsError?.userInfo
            _=self.showFailedMessage(errorInfo?["NSUnderlyingError"] as? String ?? "未知错误")
        }
        self.tableView.reloadData()
    }
    
}

extension HomeViewController:UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if(tableView == self.bondedTableView) {
            return 60
        }
        return 100
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if (tableView == self.tableView) {
            return self.devicesArray.count
        }else if (tableView == self.bondedTableView) {
//            return self.bondedArray.count
            return cachedVirtualPeripherals.count + 1
        }
        return 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if (tableView == self.tableView) {
            
            var cell = tableView.dequeueReusableCell(withIdentifier: "PeripheralTableViewCell") as? PeripheralTableViewCell
            if (cell == nil) {
                cell = PeripheralTableViewCell.loadCell()
            }
            
            cell?.selectionStyle = .none
            cell?.peripheralConnect = {[weak self] (perpheral) in
                guard let wself = self else { return }
                if (perpheral == nil) {
                    _ = wself.showFailedMessage("为获取外设对象")
                    return
                }
                if (perpheral?.state == .connected) {
                    wself.WCHManager?.disconnect(perpheral)
                }else {
                    wself.WCHManager?.connect(perpheral)
                    _ = wself.showLoadingWithText("正在连接...")
                }
            }
            
            if (self.devicesArray.count > indexPath.row) {
                let model = self.devicesArray[indexPath.row]
                
                if (self.identifiers.contains(model.peripheral.identifier)) {
                    cell?.updatePeripheralCell(model:model, isBonded: true)
                }else {
                    cell?.updatePeripheralCell(model:model, isBonded: false)
                }
            }
            
            return cell ?? UITableViewCell()
            
        }else if (tableView == self.bondedTableView) {
            if indexPath.row != cachedVirtualPeripherals.count {
                var cell = tableView.dequeueReusableCell(withIdentifier: "VirtualPeripheralCell") as? VirtualPeripheralCell
                if (cell == nil) {
                    cell = VirtualPeripheralCell.instanceFromNib()
                }
                cell?.selectionStyle = .none
                let virtualPeripheral = cachedVirtualPeripherals[indexPath.row]
                cell!.checkIconImageView.image = indexPath.row == selectedVirtualPeriperalIndex ? UIImage(named: "icon_checked") : UIImage(named: "icon_uncheck")
                cell!.nameLabel.text = virtualPeripheral.name
                let suffix = virtualPeripheral.services.count <= 1 ? "Service" : "Services"
                cell!.serviceLabel.text = "\(virtualPeripheral.services.count) \(suffix)"
                cell!.setDidCheckImgClickAction { [weak self] in
                    guard let wself = self else {return}
                    wself.selectedVirtualPeriperalIndex = indexPath.row
                    wself.bondedTableView.reloadData()
                }
                return cell!
            } else {
                
                var cell = tableView.dequeueReusableCell(withIdentifier: "NewPeripheralCell") as? NewPeripheralCell
                if (cell == nil) {
                    cell = NewPeripheralCell.instanceFromNib()
                }
                cell?.selectionStyle = .none
                return cell!
            }
        }
        
       return UITableViewCell()
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        var model:PeripheralModel?
        if (tableView == self.tableView) {
            if (self.devicesArray.count > indexPath.row) {
                model = self.devicesArray[indexPath.row] 
            }
            
            let showView = PeripheralOptionsView.instanceFromNib()
            showView?.alpha = 0
            showView?.setAdvertisementData(advertisementData: model?.advertisementData)
            self.view.addSubview(showView!)
            showView?.snp.makeConstraints({ (make) in
                make.top.equalTo(0)
                make.left.equalTo(0)
                make.right.equalTo(0)
                make.bottom.equalTo(0)
            })
            
            UIView.animate(withDuration: 0.7) {
                showView?.alpha = 1.0
            }

        }else if (tableView == self.bondedTableView) {
            guard indexPath.row != cachedVirtualPeripherals.count else {
                let virtualVC = NewVirtualPeripheralController()
                virtualVC.dismisPeriperal = { [weak self] in
                    guard  let wself = self else {
                        return
                    }
                    wself.bondedTableView.reloadData()
                }
                present(UINavigationController(rootViewController: virtualVC), animated: true, completion: nil)
                return
            }
            
            let virtualPeripheral = cachedVirtualPeripherals[indexPath.row]
            let viewController = VirtualPeripheralViewController()
            viewController.virtualPeripheral = virtualPeripheral
            navigationController?.pushViewController(viewController, animated: true)        }
    }
}

extension HomeViewController: UIScrollViewDelegate,MFMailComposeViewControllerDelegate {
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if (self.scrollView == scrollView) {
            let currentPage = floor(scrollView.contentOffset.x / scrollView.frame.width)
            segmentioView.selectedSegmentioIndex = Int(currentPage)
        }
        
        if (self.tableView == scrollView) {
            isScroll = false
        }
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if (self.scrollView == scrollView) {
            scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 0)
        }
    }
    
    func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        if (self.tableView == scrollView) {
            isScroll = true
        }
    }
    
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        controller.dismiss(animated: true)
    }
}
